package com.xc.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.config.aspect.AuthorityHandle;
import com.xc.core.bean.QueryBean;
import com.xc.core.dto.FileDto;
import com.xc.core.enums.EffectStatus;
import com.xc.core.enums.RedisPrefix;
import com.xc.core.enums.RedisTime;
import com.xc.core.utils.RedisUtils;
import com.xc.core.utils.ServiceUtils;
import com.xc.file.bean.FileBean;
import com.xc.file.bean.UpdateFileBean;
import com.xc.file.config.Constants;
import com.xc.file.dto.CdnDto;
import com.xc.file.entity.*;
import com.xc.file.enums.FailCode;
import com.xc.file.mapper.FileHashMapper;
import com.xc.file.mapper.FileMapper;
import com.xc.file.mapper.SafetyChainMapper;
import com.xc.file.mapper.ShareMapper;
import com.xc.file.model.DownloadModel;
import com.xc.file.service.FileService;
import com.xc.file.service.FolderService;
import com.xc.file.service.UserInfoService;
import com.xc.tool.utils.ObjectUtils;
import com.xc.tool.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>文件管理实现</p>
 *
 * @version v1.0
 */
@Service
@Slf4j
public class FileServiceImpl extends ServiceImpl<FileMapper, FileEntity> implements FileService {

    @Autowired
    private FileMapper fileMapper;
    @Autowired
    private Constants constants;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private SafetyChainMapper safetyChainMapper;
    @Autowired
    private ShareMapper shareMapper;
    @Autowired
    private FileHashMapper fileHashMapper;
    @Autowired
    private FolderService folderService;

    @Override
    @Transactional
    public FileEntity createFile(String userId, FileBean fileBean, boolean isVerify) {
        if (isVerify) {
            //计算当前用户使用空间
            userInfoService.verifyUserSpace(userId, fileBean.getSize());
        }
        //查询文件信息,检测文件是否重复
        FileEntity fileEntity = new FileEntity();
        fileEntity.setName(fileBean.getName());
        fileEntity.setUserId(userId);
        fileEntity.setFolderId(fileBean.getFolderId());
        FileEntity entity = fileMapper.selectOne(new QueryWrapper<>(fileEntity));
        //判断文件是否创建，已创建则重命名
        if (entity != null) {
            entity.setStatus(fileBean.getStatus());
            entity.setHashCode(fileBean.getHashCode());
            entity.setSize(fileBean.getSize());
            if (!this.retBool(fileMapper.updateById(entity))) {
                throw FailCode.REPLACE_FILE_FAIL.getOperateException();
            }
            return entity;
        }
        // 添加剩余参数保存
        fileEntity.setStatus(fileBean.getStatus());
        fileEntity.setHashCode(fileBean.getHashCode());
        fileEntity.setSize(fileBean.getSize());
        try {
            if (!this.retBool(fileMapper.insert(fileEntity))) {
                throw FailCode.CREATE_FILE_FAIL.getOperateException();
            }
        } catch (DuplicateKeyException e) {
            throw FailCode.FILE_EXIST.getOperateException();
        }
        //返回结果
        return fileEntity;
    }

    @Override
    public FileDto updateUserFile(List<String> userIds, String fileId, UpdateFileBean updateFileBean) {
        FileEntity fileEntity = getById(fileId);
        // 验证是否有操作权限
        if (!AuthorityHandle.verifyData(userIds, fileEntity.getUserId())) {
            throw FailCode.NOT_DATA_AUTHORITY.getOperateException();
        }
        fileEntity.setName(updateFileBean.getName());
        try {
            if (!this.updateById(fileEntity)) {
                throw FailCode.UPDATE_FILE_FAIL.getOperateException();
            }
        } catch (DuplicateKeyException e) {
            throw FailCode.FILE_EXIST.getOperateException();
        }
        return ObjectUtils.convert(new FileDto(), fileEntity);
    }

    @Override
    public List<FileDto> getUserFileList(String userId, List<String> userIds, QueryBean queryBean, FileEntity fileEntity) {
        QueryWrapper<FileEntity> queryWrapper = ServiceUtils.queryData(queryBean, fileEntity);
        queryWrapper.in("user_id", userIds);
        List<FileEntity> files = fileMapper.selectList(queryWrapper);
        // 设置为有效允许下载
        DownloadModel downloadModel = new DownloadModel();
        downloadModel.setFiles(files);
        String key = RedisPrefix.USER_DOWNLOAD.getKey() + userId;
        RedisUtils.set(key, downloadModel, RedisTime.USER_DOWNLOAD_CACHE.getTime());
        // 设置下载url
        List<FileDto> dtoList = ObjectUtils.convertList(files, FileDto.class);
        return setDownloadUrl(dtoList, "/user/" + userId + "/file/");
    }

    @Override
    @Transactional
    public FileEntity deleteUserFile(List<String> userIds, String fileId) {
        //获取文件信息
        FileEntity fileEntity = fileMapper.selectById(fileId);
        //验证文件是否存在
        if (fileEntity == null) {
            throw FailCode.FILE_NOT_EXIST.getOperateException();
        }
        // 验证是否有操作权限
        if (!AuthorityHandle.verifyData(userIds, fileEntity.getUserId())) {
            throw FailCode.NOT_DATA_AUTHORITY.getOperateException();
        }
        //删除文件信息
        if (!this.retBool(fileMapper.deleteById(fileId))) {
            throw FailCode.DELETE_FILE_FAIL.getOperateException();
        }
        return fileEntity;
    }

    @Override
    public DownloadModel getOpenDownload(String referer, String userId, String filePath) {
        // 去除文件后缀
        String folderPath = filePath.substring(0, filePath.lastIndexOf("/"));
        String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
        String folderId = constants.getRoot();
        if (folderPath.contains("/")) {
            FolderEntity folderEntity = folderService.getFolderByPath(userId, folderPath);
            folderId = folderEntity.getId();
        }
        FileEntity entity = new FileEntity();
        entity.setName(fileName);
        entity.setFolderId(folderId);
        entity.setUserId(userId);
        FileEntity fileEntity = fileMapper.selectOne(new QueryWrapper<>(entity));
        if (fileEntity == null) {
            throw FailCode.FILE_NOT_EXIST.getOperateException();
        }
        return verifySafetyChain(referer, fileEntity);
    }

    private DownloadModel verifySafetyChain(String referer, FileEntity fileEntity) {
        SafetyChainEntity safetyChainEntity = new SafetyChainEntity();
        safetyChainEntity.setUserId(fileEntity.getUserId());
        safetyChainEntity.setStatus(EffectStatus.VALID.getStatus());
        List<SafetyChainEntity> safetyChains = safetyChainMapper.selectList(new QueryWrapper<>(safetyChainEntity));
        String folderPath = folderService.getPathByFolderId(fileEntity.getFolderId());
        for (SafetyChainEntity safetyChain : safetyChains) {
            boolean bool = StringUtils.compareUrl(folderPath, safetyChain.getPath() + "/**");
            boolean bool1 = StringUtils.compareUrl(referer, safetyChain.getUrl());
            if (bool && bool1) {
                DownloadModel downloadModel = ObjectUtils.convert(new DownloadModel(), fileEntity);
                downloadModel.setIsCompute(true);
                return downloadModel;
            }
        }
        throw FailCode.NOT_VISIT_AUTHORITY.getOperateException();
    }

    @Override
    public DownloadModel getDownloadModel(String downloadCode, String fid, String downloadType) {
        DownloadModel downloadModel = RedisUtils.get(downloadType + downloadCode);
        if (downloadModel == null || downloadModel.getFiles() == null || downloadModel.getFiles().size() <= 0) {
            throw FailCode.DOWNLOAD_CODE_ERROR.getOperateException();
        }
        // 查看共享文件是否存在
        for (FileEntity fileEntity : downloadModel.getFiles()) {
            if (fileEntity.getId().equals(fid)) {
                return ObjectUtils.convert(downloadModel, fileEntity);
            }
        }
        throw FailCode.DOWNLOAD_CODE_ERROR.getOperateException();
    }

    @Override
    public void downloadFinish(DownloadModel downloadModel, long size) {
        if (downloadModel.getIsCompute()) {
            userInfoService.computeFreeFlow(downloadModel.getUserId(), downloadModel.getSize(), false);
        }
        if (downloadModel.getShareId() != null && downloadModel.getOpen() == 1) {
            synchronized ("") {
                ShareEntity shareEntity = shareMapper.selectById(downloadModel.getShareId());
                shareEntity.setDownloadNum(shareEntity.getDownloadNum() + 1);
                if (!this.retBool(shareMapper.updateById(shareEntity))) {
                    throw FailCode.UPDATE_SHARE_FILE_FAIL.getOperateException();
                }
            }
        }
    }

    @Override
    public List<FileDto> setDownloadUrl(List<FileDto> files, String downloadPath) {
        if (files.size() == 0) {
            return new ArrayList<>();
        }
        List<String> hashCodes = new ArrayList<>();
        for (FileDto fileDto : files) {
            hashCodes.add(fileDto.getHashCode());
        }
        //  获取下载地址
        QueryWrapper<FileHashEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("hash_code", hashCodes);
        List<FileHashEntity> fileHashList = fileHashMapper.selectList(queryWrapper);
        List<FileDto> fileDtoList = new ArrayList<>();
        for (FileDto fileDto : files) {
            for (FileHashEntity fileHashEntity : fileHashList) {
                if (fileDto.getHashCode().equals(fileHashEntity.getHashCode())) {
                    //获取后缀
                    String fileName = fileDto.getName();
                    String suffix = "";
                    if (fileName.contains(".")) {
                        int j = fileName.lastIndexOf(".");
                        suffix = fileName.substring(j);
                    }
                    fileDto.setUrl(fileHashEntity.getServerUrl() + downloadPath + fileDto.getId() + suffix);
                    fileDtoList.add(fileDto);
                }
            }
        }
        return fileDtoList;
    }

    @Override
    public CdnDto createCdnUrl(String userId, String fileId) {
        FileEntity fileEntity = fileMapper.selectById(fileId);
        // 验证是否有操作权限
        if (!userId.equals(fileEntity.getUserId())) {
            throw FailCode.NOT_DATA_AUTHORITY.getOperateException();
        }
        // 查询文件hash信息
        FileHashEntity fileHashEntity = new FileHashEntity();
        fileHashEntity.setHashCode(fileEntity.getHashCode());
        FileHashEntity hashEntity = fileHashMapper.selectOne(new QueryWrapper<>(fileHashEntity));
        // 生成下载地址
        String folderPath = folderService.getPathByFolderId(fileEntity.getFolderId());
        String filePath = folderPath + "/" + fileEntity.getName();
        String url = hashEntity.getServerUrl() + constants.getOpenCndUrl() + fileEntity.getUserId() + filePath;
        CdnDto cdnDto = new CdnDto();
        cdnDto.setCdnUrl(url);
        return cdnDto;
    }

    @Override
    public List<FileEntity> getFilesByFolderIds(String userId, List<String> folderIds) {
        FileEntity fileEntity = new FileEntity();
        fileEntity.setUserId(userId);
        QueryWrapper<FileEntity> fileWrapper = new QueryWrapper<>(fileEntity);
        fileWrapper.in("folder_id", folderIds);
        return fileMapper.selectList(fileWrapper);
    }

    @Override
    public List<FileEntity> batchCopyFile(String userId, String folderId, List<FileEntity> files) {
        for (FileEntity entity : files) {
            entity.setId(null);
            entity.setUpdateTime(null);
            entity.setCreateTime(null);
            entity.setVersion(0);
            entity.setUserId(userId);
            entity.setFolderId(folderId);
            if (!retBool(fileMapper.insert(entity))) {
                throw FailCode.COPY_FILE_FAIL.getOperateException();
            }
        }
        return files;
    }

}
